package com.bensonbasement.snorflux.server.world;

import java.io.Serializable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;

import com.bensonbasement.snorflux.server.ContentRepository;
import com.bensonbasement.snorflux.server.events.Event;
import com.bensonbasement.snorflux.server.verbs.Verb;

public class World implements Serializable {
	
	private long nextWorldElementID = 1;
	private final Map<Long,WorldElement> worldElementMap;
	private final TreeMap<Integer,Level> levelMap;
//	private final List<Level> levels;
//	private Level nextUpLevel = null;
	private Level previousLevel = null;
	private boolean turnStart = false;
		
	public World() {
		this.worldElementMap = new HashMap<Long,WorldElement>();
		this.levelMap = new TreeMap<Integer,Level>();
		//this.levels = new LinkedList<Level>();
	}
	
	public long registerWorldElement(WorldElement element) {
		long retVal = this.nextWorldElementID;
		this.nextWorldElementID ++;
		this.worldElementMap.put(retVal, element);
		return retVal;
	}
	
	public Level getLevel(int levelNum) {
		return this.levelMap.get(levelNum);
	}
	
	public void addLevel(Level level) {
		this.levelMap.put(level.getLevelNum(), level);
		//this.levels.add(level);
	}
	
	public WorldElement getWorldElement(long worldElementID) {
		return this.worldElementMap.get(worldElementID);
	}
	
	/*
	 * Start the game turn.
	 */
	public void startTurn() {
		this.turnStart = true;
	}
	
//	public Level nextLevel() {
//		Level retVal = this.nextUpLevel;
//
//		if (retVal != null) {
//			// Change the nextUpLevel.
//			this.nextUpLevel = this.levelMap.higherEntry(retVal.getLevelNum()).getValue();
//		}
//		
//		return retVal;
//	}
	
	public Level nextLevel() {
		Level next;
		if (this.turnStart) {
			next = this.levelMap.firstEntry().getValue();
			this.turnStart = false;
		}
		else if (this.previousLevel == null) {
			throw new RuntimeException("Shouldn't call nextLevel after game turn is over.");
		}
		else {
			Entry<Integer, Level> nextEntry = levelMap.higherEntry(this.previousLevel.getLevelNum());
			if (nextEntry == null) {
				next = null;
			}
			else {
				next = nextEntry.getValue();
			}
		}
		this.previousLevel = next;
		return next;
	}
	
	public void fireEvent(Event event) {
		HashSet<BrainTeam> teams = new HashSet<BrainTeam>();
		for (Level level : event.getRelevantLevels()) {
			teams.addAll(level.getAllBrainTeamsSeeingLevel());
		}
		for (BrainTeam team: teams) {
			team.receiveEvent(event);
		}
	}
	
	public Verb findVerb(Entity object, String verbName) {
		if (object == null) {
			// Objectless verb.
			return ContentRepository.getInstance().getObjectlessVerb(verbName);
		}
		else {
			return object.getVerb(verbName);
		}
	}
}
